package org.tysite.tyservice.common.exception;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;

/**
 * 全局异常格式化类
 * @author tysite
 * @date 2020/4/4 0004
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    /**
     * spring validation form-data or params 接参异常格式化
     * @param exception
     * @param request
     * @return
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public JSON validationBindException(BindException exception, HttpServletRequest request) {
        BindingResult result = exception.getBindingResult();
        return formatValidationException(result, request);
    }
    
    /**
     * spring validation @RequestBody 接参异常格式化
     * @param exception
     * @param request
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public JSON validationBodyException(MethodArgumentNotValidException exception, HttpServletRequest request) {
        BindingResult result = exception.getBindingResult();
        return formatValidationException(result, request);
    }
    
    /**
     * 业务异常BusinessExceptions 的格式化处理方法
     * @param exception
     * @param request
     * @return
     */
    @ExceptionHandler(BusinessExceptions.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public JSON businessException(BusinessExceptions exception, HttpServletRequest request) {
        JSONObject json = new JSONObject();
        StackTraceElement element = exception.getStackTrace()[0];
        json.put("status", HttpStatus.FORBIDDEN.value());
        json.put("error", "The " + element.getMethodName() +"() method of class [ " + element.getFileName() +
            " ] throws a business exception in the " +element.getLineNumber()+ " line { " + exception.getLocalizedMessage() + " }");
        json.put("message", exception.getLocalizedMessage());
        json.put("path", request.getServletPath());
        json.put("timestamp", new Date());
        return json;
    }
    
    /**
     * validation 异常信息格式化处理方法
     * @param result
     * @param request
     * @return
     */
    private JSON formatValidationException(BindingResult result, HttpServletRequest request) {
        JSONObject json = new JSONObject();
        StringBuffer errBuffer = new StringBuffer();
        StringBuffer msgBuffer = new StringBuffer();
        if (result.hasErrors()) {
            List<ObjectError> errors = result.getAllErrors();
            errors.forEach(p -> {
                FieldError fieldError = (FieldError) p;
                if (errBuffer.length() > 0) {
                    errBuffer.append("; ");
                }
                if (msgBuffer.length() > 0) {
                    msgBuffer.append("; ");
                }
                errBuffer.append("The value [");
                errBuffer.append(fieldError.getRejectedValue());
                errBuffer.append("] of { ");
                errBuffer.append(fieldError.getObjectName());
                errBuffer.append(".");
                errBuffer.append(fieldError.getField());
                errBuffer.append(" } does not conform to the specification { ");
                errBuffer.append(fieldError.getCode());
                errBuffer.append(" }");
                msgBuffer.append(fieldError.getDefaultMessage());
            });
            json.put("status", HttpStatus.BAD_REQUEST.value());
            json.put("error", errBuffer.toString());
            json.put("message", msgBuffer.toString());
            json.put("path", request.getServletPath());
            json.put("timestamp", new Date());
        }
        return json;
    }
}
